﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Media;
using System.Collections;
using System.Net;
using System.Net.NetworkInformation;


namespace NetMonitor.Server
{
    public partial class MyPoint : PictureBox
    {

        #region 构造器


        public MyPoint()
        {
            InitializeComponent();
        }

        public MyPoint(int index) : this()
        {            
            this.index = index;
            MyInit();
        }
        
        public MyPoint(int index, int type) : this(index)
        {            
            pointType = type;            
        }

        private int pointType = STANDALONE;
        public static int STANDALONE = -1;
        public static int CLIENT = 0;
        public static int SERVER = 1;

        #endregion


        #region 变量 属性


        private int index = 0;
        /// <summary>
        /// 节点的序号,每次增加节点加1
        /// </summary>
        public int Index
        {
            get { return index; }
            set { index = value; }
        }


        private string pointName;
        /// <summary>
        /// 节点的名称
        /// </summary>
        public string PointName
        {
            get { return pointName; }
            set { pointName = value; }
        }


        private string pointLocation;
        /// <summary>
        /// 节点的地理位置
        /// </summary>
        public string PointLocation
        {
            get { return pointLocation; }
            set { pointLocation = value; }
        }


        private IPAddress pointIpaddress;
        /// <summary>
        /// 节点的IP地址
        /// </summary>
        public IPAddress PointIpaddress
        {
            get { return pointIpaddress; }
            set { pointIpaddress = value; }
        }


        private Ping pingClient;


        /// <summary>
        /// 表示是否联通
        /// </summary>
        private bool isDisconnected = true;


        /// <summary>
        /// 存储通断的当前状态,用于测试是否报警
        /// </summary>
        private bool isDisconnectedNow = true;
        /// <summary>
        /// 表示是否联通
        /// </summary>
        public bool IsDisconnected
        {
            get { return isDisconnected; }
            set { isDisconnected = value; }
        }


        /// <summary>
        /// 两个提示声
        /// </summary>
        SoundPlayer soundCon, soundDiscon;


        private Point pointPosition;
        /// <summary>
        /// 节点的X,Y坐标点
        /// </summary>
        public Point PointPosition
        {
            get { return pointPosition; }
            set { pointPosition = value; }
        }


        private Bitmap normalImage;
        /// <summary>
        /// 设置节点为正常图标
        /// </summary>
        public Bitmap NormalImage
        {
            get { return normalImage; }
            set { normalImage = value; }
        }


        private Bitmap selectImage;
        /// <summary>
        /// 设置节点为鼠标点击时的图标
        /// </summary>
        public Bitmap SelectImage
        {
            get { return selectImage; }
            set { selectImage = value; }
        }


        private Bitmap disConnImage;
        /// <summary>
        /// 设置节点为报警时的图标
        /// </summary>
        public Bitmap DisConnImage
        {
            get { return disConnImage; }
            set { disConnImage = value; }
        }

        
        public ArrayList myDrawLinePoll;
        /// <summary>
        /// 定义一个集合,把所有和该点划线的MyPoint实例都储存进去
        /// </summary>
        public ArrayList MyDrawLinePoll
        {
            get { return myDrawLinePoll; }
            set { myDrawLinePoll = value; }
        }


        private Timer pointTimer;


        /// <summary>
        /// 设置节点的报警间隔时间
        /// </summary>
        /// <param name="time"></param>
        /// <returns></returns>
        public bool SetPointTimer(int time)
        {
            if (pointTimer != null && time >= 1)
            {
                pointTimer.Interval = time;
                return true;
            }
            return false;
        }



        #endregion


        #region 保留的属性

        private string soundURL;

        public string SoundURL
        {
            get { return soundURL; }
            set { soundURL = value; }
        }

        #endregion


        #region 方法


        /// <summary>
        /// 初始化
        /// </summary>
        private void MyInit()
        {
            myDrawLinePoll = new ArrayList();
            pointTimer = new Timer();
            this.MouseUp += new MouseEventHandler(MyPoint_MouseUp);
            this.MouseDown += new MouseEventHandler(MyPoint_MouseDown);

            if (pointType != CLIENT)
            {
                pingClient = new Ping();
                pingClient.PingCompleted += new PingCompletedEventHandler(pingClient_PingCompleted);
            }
          
            try
            {
                soundCon = new SoundPlayer(System.AppDomain.CurrentDomain.BaseDirectory + @"sounds\access.wav");
                soundDiscon = new SoundPlayer(System.AppDomain.CurrentDomain.BaseDirectory + @"sounds\unaccess.wav");
            }
            catch (Exception ex)
            {
                MessageBox.Show("警告...", "加载声音文件错误 :" + ex.Message, MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }


        /// <summary>
        /// 检测本point的划线poll中是否有参数mp
        /// </summary>
        /// <param name="mp"></param>
        /// <returns>如果有返回true,没有返回false</returns>
        public bool CheckIfhasMyPoint(MyPoint mp)
        {
            if (myDrawLinePoll.Count > 0)
            {
                foreach (MyPoint tp in myDrawLinePoll)
                {
                    if (tp.Equals(mp))
                    {
                        return true;
                    }
                }
            }
            return false;
        }



        /// <summary>
        /// 在划线的poll里删除指定的MyPoint实例
        /// </summary>
        /// <param name="mp"></param>
        /// <returns></returns>
        public bool RemovePointFromPool(MyPoint mp)
        {
            if (myDrawLinePoll.Count > 0)
            {
                if (myDrawLinePoll.Contains(mp))
                {
                    myDrawLinePoll.Remove(mp);
                    return true;
                }
            }
            return false;
        }


        #region 有关测试网络联通的方法

        // lryh ping忙标志（有一个Ping未返回）
        private bool isBusy = false;
        // lryh 丢包率
        private double dropRate = 0;
        // lryh 连通状态标志
        private string connectivity = CONNECTIVITY_ALARM;
        public string Connectivity
        {
            get { return connectivity;}
            set { connectivity = value; }
        }
        // lryh 短期历史记录
        private Queue<bool> queuePingLog = new Queue<bool>();
        // lryh 记录保存数量
        private const int QUEUE_PING_LOG_SIZE = 10;
        // lryh 状态变换丢包率阈值
        private const double DROP_RATE_ENTER_WARNING = 0.5;
        private const double DROP_RATE_ENTER_ALARM = 0.9;
        private const double DROP_RATE_QUIT_WARNING = 0.2;
        private const double DROP_RATE_QUIT_ALARM = 0.5;
        // lryh 连通状态
        public const string CONNECTIVITY_NORMAL = "normal";
        public const string CONNECTIVITY_WARNING = "warning";
        public const string CONNECTIVITY_ALARM = "alarm";

        private void changeState(string value)
        {
            connectivity = value;

            if (value.Equals(CONNECTIVITY_NORMAL))
            {                
                soundCon.Play();
                SetNormalImage();
            }
            else if (value.Equals(CONNECTIVITY_WARNING))
            {
                SetSelectImage();
            }
            else if (value.Equals(CONNECTIVITY_ALARM))
            {
                soundDiscon.Play();
                SetDisconImage();
            }
        }

        // lryh 添加记录，更新丢包率
        private void addPingEntry(bool value)
        {
            if (queuePingLog.Count == QUEUE_PING_LOG_SIZE)
            {
                queuePingLog.Dequeue();
                queuePingLog.Enqueue(value);
            }
            else
                queuePingLog.Enqueue(value);

            // lryh 计算丢包率
            bool[] dropLog = queuePingLog.ToArray();
            int drops = 0;
            for (int i = 0; i < dropLog.Length; i++)
            {
                if (dropLog[i]) 
                    drops++;
            }
            dropRate = (double)drops / (double)dropLog.Length;

            // lryh 转换状态
            if (connectivity == CONNECTIVITY_NORMAL)
            {
                if (dropRate > DROP_RATE_ENTER_WARNING)
                    changeState(CONNECTIVITY_WARNING);
            }
            else if (connectivity == CONNECTIVITY_WARNING)
            {
                if (dropRate >= DROP_RATE_ENTER_ALARM)
                    changeState(CONNECTIVITY_ALARM);
                else if (dropRate <= DROP_RATE_QUIT_WARNING)
                    changeState(CONNECTIVITY_NORMAL);
            }
            else if (connectivity == CONNECTIVITY_ALARM)
            {
                if (dropRate <= DROP_RATE_QUIT_ALARM)
                    changeState(CONNECTIVITY_WARNING);
            }

            Console.Out.WriteLine(pointName + "(" + pointIpaddress.ToString() + ") : " + connectivity + " (" + dropRate + ")");
        }
                

        /// <summary>
        /// 开始ping
        /// </summary>
        public void StartPing()
        {
            if (pointType == CLIENT)
            {
            }
            else
            {
                // lryh 前一个ping未返回前不再新ping
                if (pointIpaddress != null && !isBusy)
                {
                    pingClient.SendAsync(pointIpaddress, null);
                    isBusy = true;
                }
            }
        }


        /// <summary>
        /// 停止ping
        /// </summary>
        public void StopPing()
        {
            pingClient.SendAsyncCancel();
        }



        /// <summary>
        /// ICMP检测代码
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void pingClient_PingCompleted(object sender, PingCompletedEventArgs e)
        {
            //检测未出错情况下
            if (e.Error == null)
            {

                if (e.Cancelled)
                {
                    //如果点击"取消"相应语句
                    MessageBox.Show("用户取消了连通性测试");
                    return;
                }
                else
                {
                    if (e.Reply.Status == IPStatus.Success)
                    {
                        //PING返回成功
                        // isDisconnected = false;

                        // lryh 添加未丢包记录
                        addPingEntry(false);

                    }
                    else
                    {
                        //PING返回失败
                        // IsDisconnected = true;

                        // lryh 添加丢包记录
                        addPingEntry(true);
                    }
                }
                //检测连接状态并给出相应声音
                CheckConn2();
                //每次检测完都把当前状态给存储到isDisconnectedNow
                isDisconnectedNow = isDisconnected;
            }
            else
            {
                // 检测出错的情况下           
                MessageBox.Show("An error occurred while sending this ping. " + e.Error.InnerException.Message);
                Warning();
            }

            // lryh 一个ping完成后清空忙标志
            isBusy = false;
            
        }



        #endregion


        #region 鼠标点击外观变色

        void MyPoint_MouseDown(object sender, MouseEventArgs e)
        {
            SetSelectImage();
        }


        void MyPoint_MouseUp(object sender, MouseEventArgs e)
        {
            /*
            if (isDisconnected)
            {
                SetDisconImage();
            }
            else
            {
                SetNormalImage();
            }*/

            if (connectivity.Equals(CONNECTIVITY_NORMAL))
                SetNormalImage();
            else if (connectivity.Equals(CONNECTIVITY_WARNING))
                SetSelectImage();
            else if (connectivity.Equals(CONNECTIVITY_ALARM))
                SetDisconImage();
        }

        #endregion


        #region 报警检测

        /// <summary>
        /// 检测状态1,如果使用这种检测方法,每次测试完都会给检测声音
        /// </summary>
        private void CheckConn1()
        {
            if (IsDisconnected)
            {
                Warning();
            }
            else
            {
                StopWarning();
            }
        }



        /// <summary>
        /// 检测状态2,使用这种检测方法,只做通断状态发生改变的情况下才给提示
        /// </summary>
        private void CheckConn2()
        {
            /*
            if (isDisconnected != isDisconnectedNow)
            {
                if (isDisconnected == true)
                {
                    Warning();
                }
                else
                {
                    StopWarning();
                }
            }
            */ 
        }


        /// <summary>
        /// 开始报警
        /// </summary>
        private void Warning()
        {
            soundDiscon.Play();
            SetDisconImage();
        }


        /// <summary>
        /// 停止报警
        /// </summary>
        private void StopWarning()
        {
            soundCon.Play();
            SetNormalImage();
        }

        #endregion


        #region 设置图片

        private void SetNormalImage()
        {
            if (normalImage != null)
            {
                this.Image = normalImage;
            }
        }

        public void SetSelectImage()
        {
            if (selectImage != null)
            {
                this.Image = selectImage;
            }
        }

        public void SetDisconImage()
        {
            if (disConnImage != null)
            {
                this.Image = disConnImage;
            }
        }
        #endregion



        #endregion

    }
}
